/*
 * Copyright (c) 2015 Typelevel
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of
 * this software and associated documentation files (the "Software"), to deal in
 * the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
 * the Software, and to permit persons to whom the Software is furnished to do so,
 * subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

package cats
package laws
package discipline

import org.scalacheck.Prop.forAll
import org.scalacheck.Arbitrary
import org.typelevel.discipline.Laws

trait FunctorFilterTests[F[_]] extends Laws {
  def laws: FunctorFilterLaws[F]

  def functorFilter[A, B, C](implicit
    ArbFA: Arbitrary[F[A]],
    ArbFABoo: Arbitrary[PartialFunction[A, B]],
    ArbFOA: Arbitrary[F[Option[A]]],
    ArbAOB: Arbitrary[A => Option[B]],
    ArbBOC: Arbitrary[B => Option[C]],
    ArbAB: Arbitrary[A => B],
    ArbABoo: Arbitrary[A => Boolean],
    EqFA: Eq[F[A]],
    EqFB: Eq[F[B]],
    EqFC: Eq[F[C]]
  ): RuleSet =
    new DefaultRuleSet(
      name = "functorFilter",
      parent = None,
      "mapFilter composition" -> forAll(laws.mapFilterComposition[A, B, C] _),
      "mapFilter map consistency" -> forAll(laws.mapFilterMapConsistency[A, B] _),
      "collect mapFilter consistency" -> forAll(laws.collectConsistentWithMapFilter[A, B] _),
      "flattenOption mapFilter consistency" -> forAll(laws.flattenOptionConsistentWithMapFilter[A] _),
      "filter mapFilter consistency" -> forAll(laws.filterConsistentWithMapFilter[A] _),
      "filterNot mapFilter consistency" -> forAll(laws.filterNotConsistentWithFilter[A] _)
    )
}

object FunctorFilterTests {
  def apply[F[_]: FunctorFilter]: FunctorFilterTests[F] =
    new FunctorFilterTests[F] { def laws: FunctorFilterLaws[F] = FunctorFilterLaws[F] }
}
